StreamCore IPTV Documentation
A comprehensive IPTV/VOD streaming platform with Admin, Reseller, and User panels. Built with Next.js, Rust/Axum, and Kotlin.
- 9+ security fixes: bcrypt API keys, IP spoofing patched, Stripe idempotency, 2FA hardened, rate limiting.
- End-user subscription system: self-registration, free/paid packages, category-based content access.
- ClearKey DRM fully fixed across phone and TV apps (DASH manifest parser rewritten).
- Admin panel: Stripe payment settings UI, per-episode multi-stream, upload progress bars.
- 77K+ RPS on content endpoints, 82 automated tests, 0 Clippy warnings.
- Automatic v1.1.2 β v1.2.0 database migration (44 tables, FK-safe ordering).
- Release docs: Updates Overview and How to Install and Update.
VOD & Live TV
Movies, Series, Live TV channels with EPG support
Multi-Role System
Admin, Reseller, and End User roles with permissions
Stripe Payments
Integrated credit purchase system with volume discounts
Android TV + Phone Apps
Native Kotlin apps for Android TV and Android Phone
System Requirements
| Component | Requirement | Notes |
|---|---|---|
| Node.js | 20+ (LTS recommended) | For frontend build |
| Rust | 1.70+ | For backend compilation |
| RAM | 4GB minimum | 8GB+ recommended |
| Storage | 20GB+ | 100GB+ recommended for media storage |
| OS | Linux, macOS, Windows | Linux recommended for production |
Installation Overview
StreamCore consists of three main components:
Recommended: Use the Docker flow in How to Install and Update for faster setup, easier usage, and repeatable deployments.
sudo bash install.sh. It installs Docker if needed, asks for your config, updates
docker-compose.yml, and starts the stack automatically.
Backend (Rust)
API server running on port 3000
Frontend (Next.js)
Web application running on port 5000
Quick Start
β οΈ Configure secrets before starting
Set JWT_SECRET and ADMIN_DEFAULT_PASSWORD in backend/.env
before running the backend. Do not use defaults in production.
# 1. Start Backend (Terminal 1)
cd backend
cp .env.example .env
cargo build --release
./target/release/iptv-backend
# 2. Start Frontend (Terminal 2)
cd frontend
cp .env.example .env.local
npm install
npm run build
npm run start
Docker Deployment (Recommended)
For production or quick setup, use the included docker-compose.yml and root
.env.
# From the project root - Docker uses centralized configuration
# Edit docker-compose.yml directly (section x-config at the top)
# Change: postgres_password, jwt_secret, admin_password, domains
# For production with SSL:
# Uncomment the nginx-proxy and acme-companion services
# Uses nginx-proxy + Let's Encrypt
docker compose --profile proxy up -d --build
# Direct ports: 3000 (backend), 5000 (frontend)
docker compose up -d --build
- Production (proxy):
https://FRONTEND_DOMAINandhttps://BACKEND_DOMAIN - Development:
http://localhost:5000andhttp://localhost:3000
Default Login Credentials
π Default Admin Account
Username: admin
Password: Set via ADMIN_DEFAULT_PASSWORD in .env, or check console
output for auto-generated temporary password
β οΈ Change this password immediately after first login!
See Backend Environment section for details.
PostgreSQL is created and configured automatically when you start Docker. No manual setup required!
- PostgreSQL 16 runs in its own container
- All tables are created via automatic migrations
- Default admin user is created (password from docker-compose.yml)
- Default categories are created automatically
Backend Setup (Rust)
1. Install Rust
If you don't have Rust installed, install it using rustup:
# Install Rust via rustup (official installer)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Follow the prompts, then reload your shell
source $HOME/.cargo/env
# Verify installation
rustc --version
cargo --version
# Download and run rustup-init.exe from:
# https://rustup.rs/
# Or use winget:
winget install Rustlang.Rustup
# Restart terminal and verify
rustc --version
cargo --version
2. Configure Environment
cd backend
# Copy example environment file
cp .env.example .env
# Edit with your settings
nano .env
3. Build the Backend
# Development build (faster compilation, slower runtime)
cargo build
# Run development server
cargo run
# Production build (slower compilation, optimized runtime)
cargo build --release
# The binary is located at:
# ./target/release/iptv-backend
# Run production server
./target/release/iptv-backend
4. Verify Backend is Running
# Test health endpoint
curl http://localhost:3000/api/health
# Expected response:
# {"status":"ok","message":"IPTV Backend is running"}
Frontend Setup (Next.js)
1. Install Node.js
Install Node.js 20 or later:
# Install NVM
curl -o- https://nvm.sh | bash
# Reload shell
source ~/.bashrc
# Install Node.js LTS (20+)
nvm install --lts
nvm use --lts
# Verify
node --version
npm --version
2. Install Dependencies
cd frontend
# Install all dependencies
npm install
3. Configure Environment
# Copy example environment file
cp .env.example .env.local
# Edit with your backend URL
nano .env.local
frontend/.env.local
# Backend API URL
# Development:
NEXT_PUBLIC_API_URL=http://localhost:3000
# Production:
# NEXT_PUBLIC_API_URL=https://api.yourdomain.com
β οΈ Production builds
Set NEXT_PUBLIC_API_URL in production so the frontend points to the backend host. If it
is missing, the browser falls back to the current site origin, which may not be correct behind a
reverse proxy.
4. Run Frontend
Development Mode (with hot reload)
# Start development server
npm run dev
# Access at: http://localhost:5000
Production Mode
# Build for production
npm run build
# Start production server (port 5000)
npm run start
# Or specify a custom port
PORT=3001 npm run start
# Access at: http://localhost:5000
Available NPM Scripts
| Command | Description |
|---|---|
npm run dev |
Start development server with hot reload |
npm run build |
Build optimized production bundle |
npm run start |
Start production server (run build first) |
npm run lint |
Run ESLint to check code quality |
npm run test |
Run unit tests with Jest |
Database
StreamCore uses PostgreSQL 16. With Docker, the database is created and configured automatically. For manual installs, you need to set up PostgreSQL first.
Docker Setup (Automatic)
When using Docker, PostgreSQL is fully managed:
- PostgreSQL 16 container starts automatically
- Database and user are created from docker-compose.yml settings
- Backend waits for PostgreSQL to be ready (healthcheck)
- Migrations run automatically on startup
Manual Setup (Without Docker)
# Ubuntu/Debian
sudo apt install postgresql postgresql-contrib
# Start PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresql
# Create database and user
sudo -u postgres psql
CREATE USER streamcore WITH PASSWORD 'your_password';
CREATE DATABASE streamcore OWNER streamcore;
\q
Database Connection
# Local PostgreSQL
DATABASE_URL=postgres://streamcore:your_password@localhost:5432/streamcore
# Cloud PostgreSQL (Neon)
# DATABASE_URL=postgres://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require
# Cloud PostgreSQL (Supabase)
# DATABASE_URL=postgres://postgres:pass@db.xxx.supabase.co:5432/postgres
Backup Database
# Manual backup
pg_dump -U streamcore -h localhost streamcore > backup_$(date +%Y%m%d).sql
# Restore from backup
psql -U streamcore -h localhost streamcore < backup_20260209.sql
Automatic backups: The backend can create backups automatically using
pg_dump. Configure BACKUP_ENABLED, BACKUP_DIR,
BACKUP_RETENTION_DAYS, and BACKUP_INTERVAL_HOURS in docker-compose.yml or
backend/.env.
Scaling Options
PostgreSQL supports high concurrency (10,000+ users). For very large deployments, consider:
- Neon - Serverless PostgreSQL with auto-scaling
- Supabase - Managed PostgreSQL with extras
- Amazon RDS - AWS managed PostgreSQL
Systemd Services (Auto-start & Auto-restart)
Configure systemd to automatically start StreamCore on boot and restart if it crashes.
1. Backend Service
[Unit]
Description=StreamCore Backend (Rust/Axum)
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/streamcore/backend
ExecStart=/var/www/streamcore/backend/target/release/iptv-backend
Restart=always
RestartSec=5
StartLimitIntervalSec=60
StartLimitBurst=3
# Environment
Environment=RUST_LOG=info
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
2. Frontend Service
[Unit]
Description=StreamCore Web Frontend (Next.js)
After=network.target
# Optional: if you run the backend as a systemd service, add:
# After=network.target iptv-backend.service
# Wants=iptv-backend.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/streamcore/frontend
ExecStart=/usr/bin/npm run start
Restart=always
RestartSec=5
StartLimitIntervalSec=60
StartLimitBurst=3
# Environment
Environment=PORT=5000
Environment=NODE_ENV=production
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
3. Enable and Start Services
# Reload systemd to recognize new services
sudo systemctl daemon-reload
# Enable services to start on boot
sudo systemctl enable iptv-backend
sudo systemctl enable streamcore-frontend
# Start services now
sudo systemctl start iptv-backend
sudo systemctl start streamcore-frontend
# Check status
sudo systemctl status iptv-backend
sudo systemctl status streamcore-frontend
4. Useful Commands
| Command | Description |
|---|---|
sudo systemctl start iptv-backend |
Start the backend service |
sudo systemctl stop iptv-backend |
Stop the backend service |
sudo systemctl restart iptv-backend |
Restart the backend service |
sudo systemctl status iptv-backend |
Check service status |
sudo journalctl -u iptv-backend -f |
View live logs |
sudo journalctl -u iptv-backend --since "1 hour ago" |
View recent logs |
5. Auto-Restart Configuration
The services are configured with:
Restart=always- Always restart when the process exitsRestartSec=5- Wait 5 seconds before restartingStartLimitBurst=3- Max 3 restarts within the intervalStartLimitIntervalSec=60- Reset restart counter after 60 seconds
6. Deploy Script (Optional)
Create a deploy script for rebuilding and restarting services:
#!/bin/bash
set -e
echo "π Deploying StreamCore..."
# Place release files under /var/www/streamcore before running this script
# Build backend
echo "π¦ Building backend..."
cd /var/www/streamcore/backend
cargo build --release
# Build frontend
echo "π¦ Building frontend..."
cd /var/www/streamcore/frontend
npm install
npm run build
# Restart services
echo "π Restarting services..."
sudo systemctl restart iptv-backend
sudo systemctl restart streamcore-frontend
echo "β
Deployment complete!"
sudo systemctl status iptv-backend --no-pager
sudo systemctl status streamcore-frontend --no-pager
chmod +x /var/www/streamcore/deploy.sh
# Run deployment
./deploy.sh
Change App Name (Branding)
To rebrand the application with your own name, update the following files:
1. Android TV App (Recommended - Dynamic)
The Android TV app uses local.properties for dynamic branding:
Apps/tv_app/local.properties
# App branding name (used throughout the app)
branding.name=Your App Name
BuildConfig.BRANDING_NAME and @string/branding_name.
Apps/phone_app/local.properties (created from
Apps/phone_app/local.properties.template).
2. Frontend - Environment Variable (Recommended)
The frontend app name is centralized via environment variable. Simply set
NEXT_PUBLIC_APP_NAME:
frontend/.env.local
# Application name displayed throughout the UI
NEXT_PUBLIC_APP_NAME=Your App Name
- Login page title and footer
- Sidebar brand name
- Demo signup page
- Email settings default values
{{appName}} placeholder which is automatically replaced.
β οΈ Docker Users: Rebuild Required
When using Docker, the APP_NAME is set in the root .env file and is baked
into the frontend at build time. After changing APP_NAME, you must
rebuild the frontend container:
docker compose build --no-cache frontend && docker compose up -d frontend
3. Frontend - Login Page Logo & Branding
The login page displays the app logo in the header with a slate-800 backdrop container. To customize:
frontend/src/app/login/page.tsx
Logo Image
The login page uses /logo.png from the public folder:
<Image
src="/logo.png"
alt="StreamCore Logo"
width={48}
height={48}
className="object-contain"
priority
/>
Simply replace the public/logo.png file with your custom logo (same as used in the sidebar
and documentation).
Logo Container Style
The logo sits in a slate-dark container with a cyan-to-purple gradient glow effect:
// Glow effect (background)
<div className="absolute inset-0 bg-gradient-to-r from-cyan-400 to-purple-600 rounded-2xl blur-xl opacity-75 animate-pulse"></div>
// Container
<div className="relative bg-slate-800/80 backdrop-blur-md p-4 rounded-2xl">
To change the container color, edit bg-slate-800/80 to any Tailwind color. To change the
glow colors, modify the gradient colors (from-cyan-400 to-purple-600).
Login Page Branding Text
The app name in login, sidebar, and other UI elements is automatically set from the
NEXT_PUBLIC_APP_NAME environment variable (see section 2 above). No need to edit
translation files manually.
4. Frontend - PWA Manifest
frontend/public/manifest.json
{
"name": "StreamCore IPTV",
"short_name": "StreamCore",
"description": "Professional IPTV/VOD streaming platform"
}
5. Backend Banner (Optional)
backend/src/main.rs
Search for the ASCII banner and replace "StreamCore" with your app name.
Quick Find & Replace
To find all occurrences of "StreamCore" in the frontend:
# Find all StreamCore references
grep -r "StreamCore" frontend/src/
# Replace all (use with caution)
find frontend/src -type f -name "*.tsx" -o -name "*.json" | xargs sed -i 's/StreamCore/YourAppName/g'
Change Logo
To replace the logo throughout the application:
1. Prepare Your Logo
- Format: PNG with transparent background
- Minimum size: 512x512 pixels
- Aspect ratio: Square (1:1) recommended
2. Generate All Sizes
Place your logo as logo.png in the project root, then run:
# Frontend icons (web)
convert logo.png -resize 16x16 frontend/public/favicon-16x16.png
convert logo.png -resize 32x32 frontend/public/favicon-32x32.png
convert logo.png -resize 32x32 frontend/public/favicon.ico
convert logo.png -resize 180x180 frontend/public/apple-touch-icon.png
convert logo.png -resize 192x192 frontend/public/icon-192.png
convert logo.png -resize 512x512 frontend/public/icon-512.png
cp logo.png frontend/public/logo.png
# Android legacy icons (ic_launcher.png)
convert logo.png -resize 48x48 Apps/tv_app/app/src/main/res/mipmap-mdpi/ic_launcher.png
convert logo.png -resize 72x72 Apps/tv_app/app/src/main/res/mipmap-hdpi/ic_launcher.png
convert logo.png -resize 96x96 Apps/tv_app/app/src/main/res/mipmap-xhdpi/ic_launcher.png
convert logo.png -resize 144x144 Apps/tv_app/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
convert logo.png -resize 192x192 Apps/tv_app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
# Android round icons (ic_launcher_round.png)
convert logo.png -resize 48x48 Apps/tv_app/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
convert logo.png -resize 72x72 Apps/tv_app/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
convert logo.png -resize 96x96 Apps/tv_app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
convert logo.png -resize 144x144 Apps/tv_app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
convert logo.png -resize 192x192 Apps/tv_app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
# Android adaptive icon foreground (ic_launcher_foreground.png)
# Note: Foreground should have padding (~25% safe zone)
convert logo.png -resize 72x72 -gravity center -extent 108x108 Apps/tv_app/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
convert logo.png -resize 108x108 -gravity center -extent 162x162 Apps/tv_app/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
convert logo.png -resize 144x144 -gravity center -extent 216x216 Apps/tv_app/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
convert logo.png -resize 192x192 -gravity center -extent 288x288 Apps/tv_app/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
convert logo.png -resize 256x256 -gravity center -extent 384x384 Apps/tv_app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
ic_launcher.png- Legacy launcher iconic_launcher_round.png- Round launcher iconic_launcher_foreground.png- Adaptive icon foreground layeric_launcher_background.xml- Background color (edit inres/drawable/)
The adaptive icon background color can be changed in:
Apps/tv_app/app/src/main/res/drawable/ic_launcher_background.xml
3. Logo Files Location
| Platform | Location | Files |
|---|---|---|
| Web Favicon | frontend/public/ |
favicon-16x16.png, favicon-32x32.png, favicon.ico |
| PWA Icons | frontend/public/ |
icon-192.png, icon-512.png, logo.png |
| Apple Touch | frontend/public/ |
apple-touch-icon.png (180x180) |
| Android Legacy | Apps/.../res/mipmap-*/ |
ic_launcher.png, ic_launcher_round.png |
| Android Adaptive | Apps/.../res/mipmap-*/ |
ic_launcher_foreground.png |
| Android Background | Apps/.../res/drawable/ |
ic_launcher_background.xml |
Backend Environment
Docker tip: If you deploy via Docker, configure the root .env file (see How to Install and Update) instead of editing
backend/.env directly.
Configure the backend by editing backend/.env:
backend/.env
Database Configuration
# PostgreSQL (recommended)
DATABASE_URL=postgres://streamcore:change_me@localhost:5432/streamcore
# Docker internal network example
# DATABASE_URL=postgres://streamcore:change_me@postgres:5432/streamcore
Server Configuration
| Variable | Description | Example |
|---|---|---|
SERVER_ADDRESS |
IP and port for the backend server | 0.0.0.0:3000 |
PUBLIC_BASE_URL |
Public URL for generating stream links | https://api.yourdomain.com |
JWT_SECRET |
Secret key for JWT tokens (min 32 chars) | Generate with: openssl rand -hex 32 |
Stripe Payments (Optional)
# Get these from Stripe Dashboard > Developers > API keys
STRIPE_SECRET_KEY=sk_live_your_secret_key
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret
# Redirect URLs after payment
STRIPE_SUCCESS_URL=https://yourdomain.com/credits/success
STRIPE_CANCEL_URL=https://yourdomain.com/credits/cancel
# Currency (lowercase ISO code)
STRIPE_CURRENCY=usd
Configure the webhook endpoint in your Stripe Dashboard > Developers > Webhooks.
Endpoint URL:
https://api.yourdomain.com/api/payments/stripe/webhook
Additional Configuration
| Variable | Description | Default |
|---|---|---|
SKIP_MIGRATIONS |
Skip automatic database migrations on startup | false |
CONTENT_OVERVIEW_MULTIPLIER |
Multiplier for content count display (x1, x2, 1.5) | x1 |
RUST_LOG |
Logging level (trace, debug, info, warn, error) | info |
DEBUG_MODE |
Enable verbose debug behaviors (development only) | false |
CORS_ALLOWED_ORIGINS |
Comma-separated list of allowed origins for CORS (production security) | * (dev) or https://yourdomain.com |
BACKUP_ENABLED |
Enable automatic PostgreSQL backups (pg_dump) | true |
BACKUP_DIR |
Directory for backup files | ./backups |
BACKUP_RETENTION_DAYS |
Days to keep backups | 30 |
BACKUP_INTERVAL_HOURS |
Backup interval in hours | 24 |
Default Admin Password
The admin user is created automatically when the database is initialized for the first time. The password can be configured in two ways:
Option 1: Set Password via Environment Variable (Recommended)
Define ADMIN_DEFAULT_PASSWORD in your .env file before
starting the backend for the first time:
# Default admin password (set before first run)
ADMIN_DEFAULT_PASSWORD=your_secure_password_here
Option 2: Auto-Generated Temporary Password
If ADMIN_DEFAULT_PASSWORD is not set, the backend will generate a unique temporary password
and display it in the console output:
β οΈ IMPORTANT: Generated temporary admin password: tmp_187cef55b6584fdf
β οΈ Please change this password immediately after first login!
β οΈ Or set ADMIN_DEFAULT_PASSWORD environment variable before first run.
π€ Created default admin user 'admin'
β οΈ Important
The temporary password is only displayed once during the first database creation. If you miss it, you'll need to reset the password manually.
Reset Admin Password Manually
If you forgot the admin password or need to reset it:
# 1. Generate a bcrypt hash for your new password
python3 -c "import bcrypt; print(bcrypt.hashpw(b'YOUR_NEW_PASSWORD', bcrypt.gensalt()).decode())"
# 2. Update the database with the new hash
docker exec -it streamcore-postgres psql -U <POSTGRES_USER> -d <POSTGRES_DB> -c \
"UPDATE users SET password_hash='PASTE_HASH_HERE' WHERE username='admin';"
# 3. Restart the backend
Reset Database Completely
To start fresh with a new database (all data will be lost):
# Docker deployment (recommended)
docker compose down -v
docker compose up -d --build
# This recreates PostgreSQL volumes and all services from scratch.
Full Example
# Database
DATABASE_URL=postgres://streamcore:change_me@localhost:5432/streamcore
# Server
SERVER_ADDRESS=0.0.0.0:3000
PUBLIC_BASE_URL=https://api.yourdomain.com
# Security (REQUIRED - generate unique value!)
JWT_SECRET=your_64_character_random_hex_string_here
ADMIN_DEFAULT_PASSWORD=change_me_before_first_run
# Logging
RUST_LOG=iptv_backend=info,tower_http=warn,sqlx=warn
SKIP_MIGRATIONS=false
DEBUG_MODE=false
# Backups (PostgreSQL pg_dump)
BACKUP_ENABLED=true
BACKUP_DIR=./backups
BACKUP_RETENTION_DAYS=30
BACKUP_INTERVAL_HOURS=24
# Content Display
CONTENT_OVERVIEW_MULTIPLIER=x1
# CORS (production: specify allowed origins)
CORS_ALLOWED_ORIGINS=https://yourdomain.com,https://api.yourdomain.com
# Stripe Payments (leave empty to disable)
STRIPE_SECRET_KEY=sk_live_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
STRIPE_SUCCESS_URL=https://yourdomain.com/credits/success
STRIPE_CANCEL_URL=https://yourdomain.com/credits/cancel
STRIPE_CURRENCY=usd
frontend_url and app_name are
configured via the Admin Panel under Email Settings and stored in the database. UI
branding still uses NEXT_PUBLIC_APP_NAME in the frontend environment.
Frontend Environment
Docker tip: In Docker, these values come from the root .env. Use
frontend/.env.local only for non-Docker installs.
Configure the frontend by editing frontend/.env.local:
frontend/.env.local
# Backend API URL
# Development: http://localhost:3000
# Production: https://api.yourdomain.com
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
# Optional server-only base URL for Next.js (Docker/private network)
# Docker: http://backend:3000
# Local: http://localhost:3000
INTERNAL_API_URL=http://backend:3000
# Application name (displayed in UI - login, sidebar, footer, etc.)
# Default: StreamCore
NEXT_PUBLIC_APP_NAME=StreamCore
# Debug logging (optional - enables verbose console logs)
NEXT_PUBLIC_DEBUG_LOGS=false
# Media/subtitle proxy allowlist (server-only)
# Comma-separated hostnames, or "*" for local development
STREAMCORE_PROXY_ALLOWED_HOSTS=
STREAMCORE_PROXY_REQUIRE_AUTH=true
STREAMCORE_PROXY_ALLOW_PRIVATE=false
NEXT_PUBLIC_ prefix is required for environment variables
to be accessible in the browser.
Build Commands
# Development (hot reload)
npm run dev
# Production build
npm run build
# Start production server (port 5000 by default)
npm run start
# Or specify a custom port
PORT=3001 npm run start
Android Phone App Configuration NEW
Configure the Android Phone application using local.properties:
1. Create local.properties
cd app_phone/phone_app
# Copy the template
cp local.properties.template local.properties
# Edit with your settings
nano local.properties
2. Configure Branding & Backend URL
app_phone/phone_app/local.properties
# Android SDK (auto-configured by Android Studio)
sdk.dir=/path/to/your/android/sdk
# App Branding Name
branding.name=Your App Name
# Backend URL (without /api suffix)
# Development with emulator:
backend.url=http://10.0.2.2:3000
# Production:
# backend.url=https://api.yourdomain.com
BuildConfig.BRANDING_NAME= branding.nameBuildConfig.API_BASE_URL= backend.url + "/api/"BuildConfig.STREAM_BASE_URL= backend.url + "/stream/"R.string.branding_name= branding.name (for XML usage)
3. Change Package Name (applicationId)
To rebrand the app with your own package name:
Step 1: Update build.gradle
app_phone/phone_app/app/build.gradle
android {
namespace 'com.yourcompany.yourapp' // Change this
defaultConfig {
applicationId "com.yourcompany.yourapp" // Change this
...
}
}
Step 2: Rename Package Folders
# Rename the package directory structure
cd app_phone/phone_app/app/src/main/java
# Current: com/streamcore/phone/
# New: com/yourcompany/yourapp/
mv com/streamcore com/yourcompany
mv com/yourcompany/phone com/yourcompany/yourapp
Step 3: Update Imports (Android Studio)
In Android Studio: Edit β Find β Replace in Path
- Find:
com.streamcore.phone - Replace:
com.yourcompany.yourapp - Scope: Whole Project
4. Customizing App Identity (Name, Logo, Firebase)
A. Change App Name
The app name is set in two places. First, in your local.properties:
branding.name=My Cool App
Second, ensure the XML string is correct by editing:
app_phone/phone_app/app/src/main/res/values/strings.xml
<resources>
<string name="app_name">@string/branding_name</string>
</resources>
B. Change App Logo and Icons
The Android Phone app uses standardized Android icons. To replace them with your own logo:
- In Android Studio, right click on the
appfolder and go to New β Image Asset. - Set "Icon Type" to Launcher Icons (Adaptive and Legacy).
- Set your logo image in the "Foreground Layer".
- Set your desired background color in the "Background Layer".
- Click Next and Finish. This will overwrite the default StreamCore
icons in the
mipmapfolders.
C. Configure Google Services (Crashlytics / Firebase)
The app is configured to use Firebase Crashlytics to catch crashes. You must provide your own
google-services.json file, or the app will not compile.
- Go to the Firebase Console and create a new project.
- Add an Android App to the Firebase project. Crucial: Use the exact Package Name (applicationId) you configured in Step 3.
- Download the `google-services.json` file.
- Place the downloaded
google-services.jsonfile directly inside theapp_phone/phone_app/app/directory, replacing the dummy file.
5. Customize Theme Colors
Change the app's modern Jetpack Compose color scheme by editing:
app_phone/phone_app/app/src/main/java/.../theme/Color.kt
The Android Phone app uses Material 3 dynamic theming internally, but bases its core palette off the
definitions in Color.kt.
6. Build APK
The Phone project is configured to output a Single Universal APK rather than architecture splits.
cd app_phone/phone_app
# Debug build
./gradlew assembleDebug
# Release build
./gradlew assembleRelease
# The final Universal APK will be output at:
# app/build/outputs/apk/release/app-release.apk
Android TV App Configuration
Configure the Android TV application using local.properties:
1. Create local.properties
cd Apps/tv_app
# Copy the template
cp local.properties.template local.properties
# Edit with your settings
nano local.properties
2. Configure Branding & Backend URL
Apps/tv_app/local.properties
# Android SDK (auto-configured by Android Studio)
sdk.dir=/path/to/your/android/sdk
# App Branding Name
branding.name=Your App Name
# Backend URL (without /api suffix)
# Development with emulator:
backend.url=http://10.0.2.2:3000
# Production:
# backend.url=https://api.yourdomain.com
# Local network testing:
# backend.url=http://192.168.1.100:3000
BuildConfig.BRANDING_NAME= branding.nameBuildConfig.API_BASE_URL= backend.url + "/api/"BuildConfig.STREAM_BASE_URL= backend.url + "/stream/"R.string.branding_name= branding.name (for XML usage)
3. Configuration Priority
The backend URL is resolved in this order:
local.propertiesβbackend.url- Environment variable β
IPTV_BACKEND_URL - Default β
http://localhost:3000
4. App Name in strings.xml (Optional Override)
The app name is automatically set from branding.name. For additional string customization:
Apps/tv_app/app/src/main/res/values/strings.xml
<resources>
<!-- Uses @string/branding_name from local.properties by default -->
<string name="app_name">@string/branding_name</string>
</resources>
5. Change Package Name (applicationId)
To rebrand the app with your own package name:
Step 1: Update build.gradle
Apps/tv_app/app/build.gradle
android {
namespace 'com.yourcompany.yourapp' // Change this
defaultConfig {
applicationId "com.yourcompany.yourapp" // Change this
...
}
}
Step 2: Rename Package Folders
# Rename the package directory structure
cd Apps/tv_app/app/src/main/java
# Current: com/iptv/android/
# New: com/yourcompany/yourapp/
mv com/iptv com/yourcompany
mv com/yourcompany/android com/yourcompany/yourapp
Step 3: Update Imports (Android Studio)
In Android Studio: Edit β Find β Replace in Path
- Find:
com.iptv.android - Replace:
com.yourcompany.yourapp - Scope: Whole Project
6. Customize Colors & Theme
Change the app's color scheme by editing:
Apps/tv_app/app/src/main/res/values/colors.xml
<!-- Brand Colors -->
<color name="brand_primary">#1976D2</color> <!-- Primary brand color -->
<color name="brand_primary_dark">#1565C0</color> <!-- Darker variant -->
<color name="brand_secondary">#FF6B35</color> <!-- Accent color -->
<!-- Background Colors -->
<color name="background">#0A0A0A</color> <!-- Main background -->
<color name="surface">#1A1A1A</color> <!-- Card/surface background -->
7. Logo Background Colors (Splash & Login Screens)
The app uses a radial gradient background for the logo on Splash and Login screens. You can customize these colors by editing:
Apps/tv_app/app/src/main/res/values/colors.xml
<!-- Logo Background Colors (Splash & Login screens) -->
<color name="logo_background_start">#4F46E5</color> <!-- Gradient center (light) -->
<color name="logo_background_middle">#3730A3</color> <!-- Gradient middle -->
<color name="logo_background_end">#1E1B4B</color> <!-- Gradient edge (dark) -->
How the Logo Background Works
- Gradient Type: Radial gradient (center to edge)
- Color Flow:
logo_background_start(center) βlogo_background_middleβlogo_background_end(edges) - Used In: SplashScreen and UserLoginScreen
- Logo Image:
R.mipmap.ic_launcher_foreground(the PNG files)
Customize the Logo Background Color
Simply edit the three color values to create your own custom gradient:
<color name="logo_background_start">#9F7AEA</color> <!-- Light purple -->
<color name="logo_background_middle">#7C3AED</color> <!-- Medium purple -->
<color name="logo_background_end">#3B82F6</color> <!-- Blue -->
For a Solid Color (No Gradient)
Use the same color for all three values:
<color name="logo_background_start">#4F46E5</color>
<color name="logo_background_middle">#4F46E5</color>
<color name="logo_background_end">#4F46E5</color>
Update Logo Image
The logo image itself comes from the adaptive icon foreground. Replace the PNG files at:
res/mipmap-mdpi/ic_launcher_foreground.pngres/mipmap-hdpi/ic_launcher_foreground.pngres/mipmap-xhdpi/ic_launcher_foreground.pngres/mipmap-xxhdpi/ic_launcher_foreground.pngres/mipmap-xxxhdpi/ic_launcher_foreground.png
The client only needs to replace these PNG files to change the logo in Splash and Login screens without any code changes.
8. Release Signing Configuration
To build a signed APK for Google Play Store:
Step 1: Generate Keystore
keytool -genkey -v -keystore my-release-key.keystore \
-alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
Step 2: Configure Signing in build.gradle
android {
signingConfigs {
release {
storeFile file('my-release-key.keystore')
storePassword 'your-store-password'
keyAlias 'my-key-alias'
keyPassword 'your-key-password'
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
β οΈ Security Warning
Never commit your keystore or passwords to version control. Use environment variables or a separate
keystore.properties file.
9. Build APK
cd Apps/tv_app
# Debug build
./gradlew assembleDebug
# Release build (signed)
./gradlew assembleRelease
# APK locations:
# Debug: app/build/outputs/apk/debug/app-debug.apk
# Release: app/build/outputs/apk/release/app-release.apk
10. Android App Features
Live TV
Channel switching, EPG guide, favorites
VOD Playback
Movies, Series with seasons/episodes
DRM Support
Widevine, ClearKey; PlayReady best-effort on Android
Multi-language
English, Spanish, Chinese
11. System Requirements
| Requirement | Value |
|---|---|
| Minimum Android Version | Android 7.0 (API 24) |
| Target Android Version | Android 15 (API 35) |
| Kotlin Version | 2.0+ |
| Gradle Version | 8.7+ |
| Android Studio | Koala (2024.1) or newer |
12. Third-Party Libraries & Credits
| Library | Purpose | License |
|---|---|---|
| Jetpack Compose | Modern UI toolkit | Apache 2.0 |
| AndroidX Media3 | Video playback (ExoPlayer successor) | Apache 2.0 |
| Hilt | Dependency injection | Apache 2.0 |
| Retrofit | HTTP client | Apache 2.0 |
| Coil | Image loading | Apache 2.0 |
| Room | Local database | Apache 2.0 |
| DataStore | Preferences storage | Apache 2.0 |
| Timber | Logging | Apache 2.0 |
| FFmpeg Extension | Software audio/video decoding | LGPL 2.1 |
13. Project Structure
Apps/tv_app/
βββ app/
β βββ src/main/
β β βββ java/com/iptv/android/
β β β βββ core/ # Constants, utilities, network
β β β βββ data/ # Repository implementations, DTOs
β β β βββ domain/ # Use cases, models, interfaces
β β β βββ presentation/ # UI components, ViewModels, screens
β β βββ res/
β β βββ values/ # Colors, strings, themes
β β βββ mipmap-*/ # App icons
β β βββ xml/ # Network security config
β βββ build.gradle # App-level build config
β βββ proguard-rules.pro # Code obfuscation rules
βββ build.gradle # Project-level build config
βββ local.properties # Local configuration (not in package)
βββ local.properties.template # Template for local config
Admin Panel Features
Access the admin panel at /admin after logging in as admin. The admin panel provides
complete control over the platform.
Username:
adminPassword: Set via
ADMIN_DEFAULT_PASSWORD in .env, or check backend console for
auto-generated temporary passwordβ οΈ Change this password immediately after first login!
Dashboard Overview
The dashboard provides real-time statistics including:
- Total Users - All system users count
- Content Items - Movies, TV, series count
- Active Resellers - Currently active reseller count
- System Status - API, database, and content delivery indicators
Additional features are available in separate tabs:
- Billing tab - Revenue, transactions, credit purchases
- Devices tab - Active devices, connections monitoring
User Management
Manage all end users from Admin β Users:
Create New User
- Click "Add User" button
- Enter username (unique identifier)
- Set password (min 6 characters)
- Set max devices (1-10)
- Optional: set expiry date/time
- Optional: assign to reseller and select categories
- Click "Create User"
Edit User
- Extend subscription - Add days to expiration
- Change device limit - Modify max concurrent devices
- Reset password - Set new password
- Disable/Enable - Temporarily suspend account
Reseller Management
Manage resellers from Admin β Resellers:
- Create Reseller - New reseller with initial credit balance
- Add Credits - Manually add credits to reseller balance
- View Activity - See all users created by reseller
- Transaction History - Credit purchases and usage
Content Management
Manage all streaming content from Admin β Content:
Content Types
| Type | Description | Features |
|---|---|---|
| Movies (VOD) | Single video content | TMDB metadata, posters, trailers |
| Series | Episodes organized by seasons | Auto-episode numbering, TMDB integration |
| Live TV | Live streaming channels | EPG integration, categories |
| Events | Time-limited live streams | PPV support, scheduled visibility |
| Kids | Child-friendly content | Parental filtering, dedicated section |
| Anime | Anime-specific content | Separate anime section |
Adding Content
- Click "Add Content" β Select type
- Enter title and description
- Paste stream URL (HLS/DASH/Direct)
- Add poster/backdrop images (URL or upload)
- Select category and tags
- Enable/disable visibility
- Save content
TMDB Integration
Auto-fetch metadata from The Movie Database:
- Click "Search TMDB" when adding content
- Enter movie/series name
- Select from results
- Metadata auto-fills (title, description, poster, year, rating)
β οΈ TMDB Usage for Commercial Products
- TMDB API keys are not bundled. Each buyer must add their own key in the admin panel.
- Using TMDB data in commercial products requires complying with TMDB's Terms of Service; obtain permission if your usage needs it.
- Add TMDB's required attribution in your live site: "This product uses the TMDB API but is not endorsed or certified by TMDB."
- Only import artwork/metadata when you have rights to use it; remove or replace any unlicensed images before going live.
Media Scanner
Bulk import content from local folders:
- Go to Admin β Media Scanner
- Enter folder path on server
- Select content type (Movies/Series/Kids/Anime)
- Enable TMDB auto-match (optional)
- Click "Scan" to import all files
File Naming Conventions
The scanner extracts title and year from filenames. Use these formats:
Movies / Kids / Anime:
/media/movies/
βββ Bureau 749 (2024).mp4
βββ Dracula (2025).mkv
βββ Frozen (2013).mp4
βββ Coco (2017).mp4
Format: Title (Year).extension
TV Series:
/media/tvshows/
βββ Breaking Bad S01E01.mp4
βββ Breaking Bad S01E02.mp4
βββ Game of Thrones S01E01.mkv
βββ The Office S02E05.mp4
Format: Show Name S##E##.extension
Alternative Series Structure (folder-based):
/media/tvshows/
βββ Breaking Bad/
βββ Season 1/
β βββ S01E01.mp4
β βββ S01E02.mp4
βββ Season 2/
βββ S02E01.mp4
Supported Extensions: .mp4, .mkv, .avi, .mov, .webm, .m4v, .ts
Media Watcher
Auto-import new files when added to watched folders:
- Go to Admin β Media Watcher
- Add folder paths to monitor
- Set content type for each folder
- Enable watcher
- New files are automatically imported
EPG Management
Electronic Program Guide for Live TV:
- Go to Admin β EPG Sources
- Add EPG URL (XMLTV format)
- Set refresh interval (minutes)
- Map channels to EPG IDs
- EPG auto-updates on schedule
Security Panel
Monitor and manage security from Admin β Security:
- Stats Overview - Security metrics and incident counts
- Security Incidents - Failed logins, suspicious activity logs
- IP Bans - Temporary or permanent IP blocks with expiration
- Blacklisted Devices - Block specific device IDs permanently
System Configuration
Global settings from Admin β Settings:
- Credit Defaults - Default device count and per-device credit factors
- Credit Purchase Pricing - Base price per credit and volume discount tiers
- TMDB Settings - API key, mode, language, and metadata path
- Login Backdrops - Series/movie hero background lists
- Public Endpoints - Enable/disable public demo and redeem routes
Additional Admin Features
The admin panel includes these additional management features:
- Email Settings (Admin β Email) - SMTP configuration for password reset and 2FA emails
- Billing Dashboard (Admin β Billing) - Revenue tracking, online/offline payments, credit transactions
- Master API Keys (Admin β Master Keys) - API key management for external integrations
- Gift Codes (Admin β Gift Codes) - Create and manage promotional codes for subscriptions
- Demos Management (Admin β Demos) - Monitor and manage demo/trial accounts
- Device Management (Admin β Devices) - View all devices, active connections, device stats
- Activity Logs (Admin β Logs) - Audit trail of all admin and user actions
- Support Tickets (Admin β Tickets) - Internal ticket system for user support
Reseller Panel Features
Resellers can manage their own users, purchase credits, and track their business performance. Access at
/reseller after logging in as a reseller.
The reseller panel features a modern wallet-style interface with real-time statistics, quick actions, and comprehensive analytics.
Dashboard Overview
The reseller dashboard displays:
- Credit Balance - Available credits with "Add Credits" quick action
- Total Users - Number of users created by this reseller
- Active Users - Users with non-expired subscriptions
- Expiring Soon - Users expiring in the next 7 days
- Active Demos - Current trial accounts
End User Management
Create and manage users from Reseller β Users:
Create New User
- Click "Create User" button
- Enter unique username (real-time availability check)
- Set password (or auto-generate)
- Optional: Enter email (for password reset)
- Select subscription duration: 1-12 months
- Set device limit: 3, 5, 6, 7, 8, 9, or 10 devices
- Select content categories to assign
- Click "Create" - credits are deducted automatically
User Actions
- Extend Subscription - Add days (costs credits)
- Reset Password - Generate new password
- View Devices - See registered devices
- Disable User - Temporarily suspend access
- Delete User - Permanently remove (no credit refund)
Credit System
Credits are the currency for creating and extending users. The cost is calculated based on months and device count:
Credit Calculation Formula
Base: 1 credit per month for 3 devices
Extra devices: +0.25 credits per month for each device above 3
Formula: months Γ (1 + (devices - 3) Γ 0.25)
Example Calculations
| Months | Devices | Credits |
|---|---|---|
| 1 month | 3 devices | 1 credit |
| 1 month | 5 devices | 1.5 credits |
| 6 months | 3 devices | 6 credits |
| 6 months | 5 devices | 9 credits |
| 12 months | 10 devices | 33 credits |
Buy Credits
- Click "Add Credits" or go to Reseller β Buy Credits
- Select credit package or enter custom amount
- Volume discounts apply automatically (default tiers, configurable in Admin Panel):
- 100+ credits: 5% discount
- 250+ credits: 7% discount
- 500+ credits: 10% discount
- 1000+ credits: 15% discount
- Proceed to Stripe Checkout
- Complete payment - credits added instantly
Demo Management
Resellers can offer limited-time demos:
- Daily Limit - Maximum demos per day (set by admin)
- Demo Duration - Temporary accounts that expire after 2 hours (fixed duration)
- Auto-Expiration - Demos expire automatically
- No Credit Cost - Demos don't consume credits
- Demo Stats - Track active demos and usage
Activity Logs
Track all actions from Reseller β Activity:
- User creation/modification history
- Credit purchases and usage
- Login history
- Timestamps and IP addresses
Expiration Monitoring
Monitor user expirations from Reseller β Expiring. Users are categorized by urgency:
- Expired - Subscriptions that have already expired
- Critical - Expiring within 2 days (requires immediate action)
- Warning - Expiring in 3-5 days
- Good - More than 5 days remaining
Support Tickets
Contact admin support from Reseller β Support:
- Click "New Ticket"
- Select category (Billing, Technical, Other)
- Describe your issue
- Submit - admin receives notification
- Track ticket status and responses
Reseller API Keys
Resellers can create API keys to integrate their own payment systems and automate user management through the Public API v1. This allows resellers to build custom billing workflows, integrate with payment gateways, and manage users programmatically.
API Keys allow resellers to call the Public API (
/api/v1/*) from their own systems. This is
useful for:
- Integrating with custom payment processors (PayPal, MercadoPago, etc.)
- Building automated billing systems
- Creating users automatically after payment confirmation
- Extending subscriptions via webhooks
- Building custom reseller dashboards
Accessing API Key Management
Navigate to Reseller β API Keys in the reseller dashboard.
Creating an API Key
- Click "Create API Key" button
- Enter a descriptive Key Name (e.g., "Payment Webhook", "External System")
- Select Permissions:
users:read- List and view usersusers:create- Create new usersusers:update- Update user status and extend subscriptionsusers:extend- Extend user subscriptionsusers:delete- Delete usersusers:categories- Manage user content categoriescredits:read- View credit balance and calculate costscategories:read- List available content categoriesdemos:read- List and view demo usersdemos:create- Create demo users (free, time-limited)demos:delete- Delete demo users
- Configure Allowed Origins (CORS):
*- Allow from any origin (development only; not recommended for production)https://your-domain.com- Restrict to specific domain- Multiple origins:
https://domain1.com,https://domain2.comor JSON array - Empty or invalid
allowed_originsvalues are rejected
- Optional: Add IP Whitelist for additional security
- Configure Rate Limits:
- Requests per minute (default: 60)
- Requests per day (default: 10,000)
- Optional: Set Expiration Date
- Click "Create Key"
β οΈ Important: Save Your Secret Key!
The full API key is shown only once when created. Copy and store it securely - you won't be able to see it again.
If you lose the key, you'll need to regenerate it (which invalidates the old key).
API Key Security Features
| Feature | Description |
|---|---|
| SHA-256 Hashing | API keys are hashed before storage - even database access won't reveal keys |
| Prefix Display | Only first 8 characters are visible for identification |
| CORS Validation | Requests are validated against allowed origins |
| IP Whitelist | Optional restriction to specific IP addresses |
| Rate Limiting | Per-minute and per-day limits enforced per key and per IP |
| Usage Logging | All API key requests are logged; failures block the request |
| Expiration | Optional automatic key expiration |
| Permission Scopes | Granular permissions for each key |
| Audit Logging | All API operations are logged |
Managing API Keys
From the API Keys dashboard you can:
- View Keys - See all keys with their prefix, permissions, and status
- Toggle Active/Inactive - Temporarily disable a key without deleting it
- View Statistics - See total requests and last used timestamp
- Regenerate Key - Generate a new secret (invalidates old key)
- Delete Key - Permanently remove an API key
Using the API Key
Include the API key in the X-API-Key header for all Public API v1 requests:
X-API-Key: your-api-key-here
Example: Create User After Payment
# Create a new user via API
curl -X POST https://your-domain.com/api/v1/users \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key-here" \
-d '{
"username": "newuser123",
"password": "securepassword",
"subscription_months": 3,
"max_devices": 5
}'
Example: Extend Subscription (Webhook)
// Payment webhook handler
async function handlePaymentWebhook(payment) {
const userId = payment.metadata.user_id;
const months = payment.metadata.months;
const response = await fetch(`https://your-domain.com/api/v1/users/${userId}/extend`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.STREAMCORE_API_KEY
},
body: JSON.stringify({
days: months * 30
})
});
if (response.ok) {
console.log('Subscription extended successfully');
}
}
Example: Check Credit Balance
import requests
API_KEY = "your-api-key-here"
BASE_URL = "https://your-domain.com/api/v1"
# Get credit balance
response = requests.get(
f"{BASE_URL}/credits/balance",
headers={"X-API-Key": API_KEY}
)
data = response.json()
print(f"Available credits: {data['balance']}")
Best Practices
- Use Environment Variables - Never hardcode API keys in source code
- Minimal Permissions - Only grant the permissions you need
- IP Whitelisting - Use for server-to-server integrations
- Key Rotation - Periodically regenerate keys for security
- Monitor Usage - Review request counts and last used timestamps
- Separate Keys - Use different keys for different integrations
User Panel Features
End users access streaming content through a modern, responsive interface at /user. The
interface is optimized for both desktop and mobile devices.
Home Dashboard
The user home page features:
- Hero Banner - Featured content with auto-rotation
- Continue Watching - Resume content where you left off
- Recently Added - New content in the library
- Categories - Quick access to content types
- Recommendations - Based on watch history
Content Browsing
Movies (VOD)
- Grid view with poster thumbnails
- Filter by genre, year, rating
- Search by title
- Sort by date added, rating, title
Series
- Series overview with poster and description
- Season selector dropdown
- Episode list with thumbnails
- Auto-play next episode
Live TV
- Channel grid or list view
- Category filtering (News, Sports, Entertainment, etc.)
- EPG guide - What's playing now and next
- Channel search
- Favorite channels
Video Player
Modern player with full controls:
- Subtitles - Multiple language options with flag indicators
- Audio Tracks - Switch audio languages
- Playback Speed - 0.5x, 0.75x, 1x, 1.25x, 1.5x, 2x
- Skip Controls - Skip forward/backward 10 seconds
- Fullscreen - Click fullscreen button or browser F11
- Progress Bar - Click or drag to seek
- Volume Control - Slider with mute toggle
Favorites
Save content for quick access:
- Click the heart icon on any content
- Access favorites from User β Favorites
- Remove by clicking heart again
Watch Progress & Resume
Automatic progress tracking with resume functionality:
- Progress saved automatically every 30 seconds
- Resume playback from where you left off
- Progress synced between devices
- View watch history and clear if needed
- Continue Watching section on home page
Device Management
Manage registered devices from User β Devices:
- View Devices - See all registered devices
- Device Info - Name, type, last active
- Remove Device - Free up device slot
- Device Limit - Shows X of Y devices used
New devices are registered automatically on first login. If you reach your device limit, remove an old device before logging in on a new one.
Profile Settings
Manage your account from User β Profile:
- Change Password - Update your password
- Subscription Info - View expiration date and status
- Account Details - View username and device limit
Language Selection: Switch interface language (EN, ES, ZH) from the Home or Devices page.
2FA is available only for Admin and Reseller accounts. Regular end users do not have access to 2FA settings.
Content Pages & Routes
The user panel includes these content pages:
- Movies (/user/movies) - VOD movie library
- Shows (/user/shows) - TV series with seasons/episodes
- Live TV (/user/live) - Live streaming channels with EPG
- Kids (/user/kids) - Family-friendly content section
- Anime (/user/anime) - Dedicated anime browsing
- Events (/user/events) - Live events and PPV content
- Content (/user/content) - Browse all content by category
- Watch (/user/content/[id]/watch) - Video player page
- History (/user/history) - Complete watch history
- Search (/user/search) - Search across all content
- Products (/user/products) - Available subscriptions
Search
Global search across all content:
- Search movies, series, channels
- Instant results as you type
- Filter by content type
- Recent search history
Additional Public Pages
These pages are accessible without user login:
- /login - User authentication page
- /forgot-password - Request password reset email
- /reset-password - Set new password (from email link)
- /demo - Demo account signup (if enabled)
- /redeem - Redeem gift codes for subscription
- /banned - Displayed when user account is banned
- /content - Public content browsing (limited)
- /credits/success - Stripe payment success redirect
- /credits/cancel - Stripe payment cancel redirect
Stripe Payments Setup
Enable credit purchases for resellers via Stripe Checkout.
1. Create Stripe Account
- Go to stripe.com and create an account
- Complete business verification
- Get your API keys from Dashboard β Developers β API keys
2. Configure Webhook
- Go to Dashboard β Developers β Webhooks
- Click "Add endpoint"
- URL:
https://api.yourdomain.com/api/payments/stripe/webhook - Select event:
checkout.session.completed - Copy the webhook signing secret
3. Update Environment
STRIPE_SECRET_KEY=sk_live_your_secret_key
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_signing_secret
STRIPE_SUCCESS_URL=https://yourdomain.com/credits/success
STRIPE_CANCEL_URL=https://yourdomain.com/credits/cancel
STRIPE_CURRENCY=usd
4. Configure Pricing
In Admin Panel β System Configuration β Credits Pricing:
- Set base price per credit
- Configure volume discount tiers
Email (SMTP) Configuration
Configure SMTP to enable password reset emails and 2FA notifications.
SMTP is configured entirely from the Admin Panel. No environment variables required!
Go to: Admin Panel β Settings β Email Configuration
Configuration Steps
- Log in as Admin
- Navigate to Admin Panel β Settings β Email
- Enable SMTP and fill in the settings
- Click "Test Connection" to verify
- Save the configuration
Required Settings
| Field | Description | Example |
|---|---|---|
| SMTP Host | Mail server hostname | smtp.gmail.com |
| Port | SMTP port (usually 587 for TLS) | 587 |
| Username | SMTP authentication username | your-email@gmail.com |
| Password | SMTP password or app password | xxxx xxxx xxxx xxxx |
| From Name | Display name in emails | StreamCore |
| From Email | Sender email address | noreply@yourdomain.com |
| Use TLS | Enable TLS encryption | Yes |
| Frontend URL | Used in password reset links | https://yourdomain.com |
| App Name | Used in email subjects and 2FA | StreamCore |
Gmail Setup
To use Gmail as your SMTP server:
- Enable 2-Step Verification in your Google Account
- Go to Google App Passwords
- Generate a new App Password for "Mail"
- Use that 16-character password as
SMTP_PASSWORD
Other SMTP Providers
| Provider | Host | Port | Notes |
|---|---|---|---|
| Gmail | smtp.gmail.com |
587 | Requires App Password |
| SendGrid | smtp.sendgrid.net |
587 | Use API key as password |
| Mailgun | smtp.mailgun.org |
587 | Domain-specific credentials |
| Amazon SES | email-smtp.{region}.amazonaws.com |
587 | SMTP credentials from AWS console |
- Password reset emails with secure tokens
- 2FA enabled/disabled confirmation emails
- Beautiful HTML email templates
Two-Factor Authentication (2FA)
StreamCore supports TOTP-based two-factor authentication for enhanced account security.
How It Works
- Setup: User scans QR code with authenticator app (Google Authenticator, Authy, etc.)
- Verification: User enters 6-digit code to enable 2FA
- Login: After password, user must enter current 2FA code
- Backup Codes: 8 one-time backup codes are generated for recovery
User Experience
Enable 2FA
Users enable 2FA from their profile settings page
Authenticator App
Compatible with Google Authenticator, Authy, Microsoft Authenticator
Backup Codes
8 one-time backup codes for account recovery
Email Notifications
Users receive email when 2FA is enabled/disabled
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/auth/2fa/status |
Get 2FA status for current user |
POST |
/api/auth/2fa/setup |
Generate secret and QR code |
POST |
/api/auth/2fa/verify |
Verify code and enable 2FA |
POST |
/api/auth/2fa/disable |
Disable 2FA (requires code) |
POST |
/api/auth/2fa/backup-codes |
Regenerate backup codes |
Password Reset
Users can reset their password via email:
- User clicks "Forgot Password" on login page
- User enters their email address
- System sends email with secure reset link (expires in 1 hour)
- User clicks link and sets new password
POST /api/auth/forgot-password # Request reset email
POST /api/auth/verify-reset-token # Verify token validity
POST /api/auth/reset-password # Set new password
β οΈ Security Notes
- Reset tokens expire after 1 hour
- Each token can only be used once
- All previous tokens are invalidated when a new one is generated
- SMTP must be configured for password reset to work
Security Best Practices
β οΈ Critical Security Steps
- Change default admin password immediately after installation
- Generate unique JWT_SECRET:
openssl rand -hex 32 - Use HTTPS in production (via nginx/Caddy reverse proxy)
- Configure CORS to only allow your domain
CORS Configuration
CORS is configured via environment variable. Set CORS_ALLOWED_ORIGINS in your
.env file:
# Development (allow all origins - NOT for production!)
CORS_ALLOWED_ORIGINS=*
# Production (comma-separated list of allowed origins)
CORS_ALLOWED_ORIGINS=https://yourdomain.com,https://api.yourdomain.com
β οΈ Security Warning
Never use CORS_ALLOWED_ORIGINS=* in production. The backend will log a warning if
permissive CORS is enabled.
Session & Token Security
- JWT Tokens - Access tokens expire after 24 hours
- Auth Cookies - Frontend stores tokens in cookies with:
- Max-Age: 7 days
- SameSite: Lax
- Secure: true (in production)
- Password Hashing - Uses bcrypt with default cost factor (10 rounds)
Firewall Rules
- Backend API: Port
3000 - Frontend Web: Port
5000(or 3000 in dev mode) - SSH: Port
22 - HTTP: Port
80(for nginx proxy) - HTTPS: Port
443(for nginx proxy with SSL)
Option A: With Nginx Reverse Proxy (Recommended)
If using nginx as a reverse proxy, you only need to open ports 80 and 443. Nginx will forward requests to the backend (3000) and frontend (5000) internally.
# Allow SSH
sudo ufw allow 22
# Allow HTTP/HTTPS (nginx handles proxying)
sudo ufw allow 80
sudo ufw allow 443
# Backend (3000) and Frontend (5000) stay internal
# No need to expose them - nginx proxies the traffic
# Enable firewall
sudo ufw enable
# Check status
sudo ufw status
Option B: Without Reverse Proxy (Direct Access)
If you're NOT using nginx/Caddy and want to access the services directly, you must open the backend and frontend ports:
# Allow SSH
sudo ufw allow 22
# Allow Backend API (Rust/Axum)
sudo ufw allow 3000
# Allow Frontend Web (Next.js)
sudo ufw allow 5000
# Optional: Also allow 80/443 if you plan to add nginx later
sudo ufw allow 80
sudo ufw allow 443
# Enable firewall
sudo ufw enable
# Check status
sudo ufw status
β οΈ Security Warning
Exposing ports 3000 and 5000 directly is not recommended for production because:
- No SSL/HTTPS encryption (data sent in plain text)
- No rate limiting or DDoS protection
- Exposes internal service ports to the internet
Recommended: Use nginx or Caddy as a reverse proxy with SSL certificates (Let's Encrypt).
Port Summary Table
| Port | Service | With Nginx | Without Nginx |
|---|---|---|---|
22 |
SSH | β Open | β Open |
80 |
HTTP (nginx) | β Open | Optional |
443 |
HTTPS (nginx + SSL) | β Open | Optional |
3000 |
Backend API | β Internal only | β Open |
5000 |
Frontend Web | β Internal only | β Open |
Quick Test (Without Firewall Changes)
To quickly test if the services are accessible:
# Test backend locally
curl http://localhost:3000/api/health
# Test backend from another machine (replace YOUR_SERVER_IP)
curl http://YOUR_SERVER_IP:3000/api/health
# Test frontend
curl http://YOUR_SERVER_IP:5000
# If connection refused, open the ports:
sudo ufw allow 3000
sudo ufw allow 5000
Production Deployment
For a production environment, we recommend using Nginx as a reverse proxy and SSL terminator. This allows you to serve both the frontend and backend on standard ports (80/443) with a custom domain.
1. Nginx Reverse Proxy Configuration
server {
listen 80;
server_name yourdomain.com api.yourdomain.com;
return 301 https://$server_name$request_uri;
}
# Frontend (yourdomain.com)
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
# Backend API (api.yourdomain.com)
server {
listen 443 ssl http2;
server_name api.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
2. Process Management
Ensure you have configured the Systemd services as described in the Systemd Services section. This will ensure your application starts automatically and restarts on failure.
sudo systemctl enable iptv-backend
sudo systemctl enable streamcore-frontend
sudo systemctl start iptv-backend
sudo systemctl start streamcore-frontend
3. SSL Certificates (Let's Encrypt)
Generate free SSL certificates using Certbot:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d api.yourdomain.com
Android App Build Guide
Build the native Android TV app from source code.
Apps/tv_app, phone app in
Apps/phone_app. This section focuses on TV build flow; the phone app follows the same
Gradle process.
Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Android Studio | Hedgehog (2023.1.1) or newer | Download |
| JDK | 17+ | Bundled with Android Studio |
| Android SDK | API 35 (Android 15) | Compile & Target SDK |
| Min SDK | API 24 (Android 7.0) | Minimum supported |
| Gradle | 8.2+ | Bundled with project |
1. Open Project
- Open Android Studio
- Select "Open" and navigate to
Apps/tv_app - Wait for Gradle sync to complete (may take several minutes)
- If prompted, install any missing SDK components
2. Configure Backend URL
# Copy from template
cp local.properties.template local.properties
# Edit with your backend URL
backend.url=https://api.yourdomain.com
# For local development with emulator:
# backend.url=http://10.0.2.2:3000
# For local development with physical device:
# backend.url=http://YOUR_COMPUTER_IP:3000
3. Configure App Identity (Optional)
To customize the app package name and branding:
Apps/tv_app/app/build.gradle
android {
namespace 'com.yourcompany.yourbrand'
defaultConfig {
applicationId 'com.yourcompany.yourbrand'
// ...
}
}
build.gradle), not Kotlin DSL. Use
single quotes without = signs in Groovy syntax.
4. Build Debug APK
# Using Gradle wrapper
./gradlew assembleDebug
# APK output location:
# app/build/outputs/apk/debug/app-debug.apk
Or in Android Studio: Build β Build Bundle(s) / APK(s) β Build APK(s)
5. Build Release APK/AAB
Generate Signing Key (first time only)
keytool -genkey -v -keystore release-key.jks -keyalg RSA \
-keysize 2048 -validity 10000 -alias release
# Follow prompts to set passwords
# Store release-key.jks securely - you need it for all future updates!
Configure Signing
storePassword=your_keystore_password
keyPassword=your_key_password
keyAlias=release
storeFile=../release-key.jks
Build Release
# Build signed APK
./gradlew assembleRelease
# Build Android App Bundle (for Play Store)
./gradlew bundleRelease
# Output locations:
# APK: app/build/outputs/apk/release/app-release.apk
# AAB: app/build/outputs/bundle/release/app-release.aab
6. Install on Device
# Install debug APK via ADB
adb install app/build/outputs/apk/debug/app-debug.apk
# Install release APK
adb install app/build/outputs/apk/release/app-release.apk
# For Android TV, enable ADB debugging in TV settings first
β οΈ Important Notes
- Keep your keystore safe! Losing it means you can't update your app
- Never commit keystore.properties to version control
- Test on real devices before release, especially Android TV
Android App Features
StreamCore includes Android TV and Android Phone apps, both built with Kotlin and Jetpack Compose.
Device Registration
- Launch the app and log in
- Enter a device name and register it
- If you are at the device limit, select a device to remove
- Once registered, the device is linked to your account
Navigation
- D-pad Navigation - Full support for TV remote
- Voice Search - Press microphone button to search
- Back Button - Returns to previous screen
- Home Button - Returns to home screen
Player Features
- Media3 (ExoPlayer) - Primary player with hardware acceleration priority
- FFmpeg Decoder - Integrated software fallback for unsupported codecs
- DRM-ready playback (bring your own license server):
- ClearKey DRM (Web and Android) with your license keys/endpoint
- Widevine (Web and Android) when you supply a license server URL
- PlayReady (best-effort on Android) when you supply a license server URL
- AES-128 HLS encryption
- Quality Selection - Manual quality switching
- Subtitles - Multi-language subtitle support
- Audio Tracks - Multi-language audio switching
Content Sections
- Home - Hero banner + content carousels
- Live TV - Channel grid with EPG
- Movies - VOD content library
- Series - TV shows with seasons/episodes
- Events - Live events and PPV content
- Favorites - User's favorite content
- Search - Global search with voice support
- Profile - User account and subscription info
- Settings - App configuration
Architecture
The app follows Clean Architecture with MVVM pattern:
- Presentation Layer - Jetpack Compose UI + ViewModels
- Domain Layer - Use cases, models, repository interfaces
- Data Layer - Repository implementations, API clients, DTOs
- Dependency Injection - Hilt for DI across all modules
Offline Support
- Channel logos cached locally
- Content metadata cached in Room database
- User preferences stored in DataStore
- Graceful offline handling
API Reference
The backend exposes a RESTful API at /api.
This section covers key endpoints. The backend provides a comprehensive REST API for admin, reseller, content, streaming, and TMDB integration.
Authentication
| Endpoint | Method | Description |
|---|---|---|
/api/auth/login |
POST | Login with username/password, returns JWT access token |
/api/auth/refresh |
POST | Refresh access token using the current valid token |
/api/auth/logout |
POST | Invalidate current session |
/api/auth/2fa/setup |
POST | Initialize 2FA setup, returns QR code |
/api/auth/2fa/verify |
POST | Verify 2FA code during login |
/api/auth/forgot-password |
POST | Request password reset email |
/api/auth/verify-reset-token |
POST | Verify password reset token validity |
/api/auth/reset-password |
POST | Set new password with valid token |
/api/health |
GET | Health check endpoint (no auth required) |
Content
| Endpoint | Method | Description |
|---|---|---|
/api/content |
GET | List all content (paginated) |
/api/content/{id} |
GET | Get content details |
/api/content |
POST | Create new content (admin) |
/api/content/{id} |
PUT | Update content (admin) |
/api/content/{id} |
DELETE | Delete content (admin) |
/api/series/{id}/seasons |
GET | Get series seasons with episodes |
/api/delivery/discovery |
GET | Get discovery overview (featured, recent, categories) |
User Management
| Endpoint | Method | Description |
|---|---|---|
/api/admin/users |
GET | List all users (admin only) |
/api/reseller/users |
GET | List reseller's users |
/api/admin/users |
POST | Create user (admin) |
/api/reseller/users |
POST | Create user (reseller) |
/api/user/profile |
GET | Get current user profile |
/api/devices |
GET | List user devices |
/api/user/favorites |
GET/POST/DELETE | Manage favorites |
Additional Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/admin/smtp |
GET/PUT | Get/Update SMTP configuration |
/api/admin/smtp/test |
POST | Test SMTP connection |
/api/user/progress |
POST | Save watch progress for resume |
/api/user/progress/:id |
GET | Get progress for content |
/api/user/continue-watching |
GET | Get continue watching list |
/api/user/history |
GET | Get viewing history log |
/api/user/history/clear |
DELETE | Clear watch history |
/api/redeem/validate |
POST | Validate gift code |
/api/redeem |
POST | Redeem gift code and create account |
/api/demo |
POST | Create demo account (public) |
/api/demo/status |
GET | Check if demo is enabled |
Public API v1 (Reseller Integration)
The Public API v1 allows resellers to manage users programmatically using API keys. These endpoints use
X-API-Key header authentication instead of JWT.
All
/api/v1/* endpoints require a valid API key in the X-API-Key header.
Create API keys from the Reseller β API Keys section.
User Management Endpoints
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/v1/users |
GET | users:read |
List users with filters, search, and pagination |
/api/v1/users/{id} |
GET | users:read |
Get user details by ID |
/api/v1/users |
POST | users:create |
Create a new user (deducts credits) |
/api/v1/users/{id} |
PUT | users:update |
Update user (email, password, max_devices, active) |
/api/v1/users/{id}/extend |
POST | users:extend |
Extend user subscription (deducts credits) |
/api/v1/users/{id}/status |
PUT | users:update |
Update user status (enable/disable) |
/api/v1/users/{id}/reset-password |
POST | users:update |
Reset user password (auto-generate or set custom) |
/api/v1/users/{id}/categories |
GET | users:read |
Get user with assigned categories |
/api/v1/users/{id}/categories |
PUT | users:categories |
Update user's content categories |
/api/v1/users/{id} |
DELETE | users:delete |
Delete a user |
Categories & Credits Endpoints
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/v1/categories |
GET | categories:read |
List all available content categories |
/api/v1/credits/balance |
GET | credits:read |
Get current credit balance |
/api/v1/credits/calculate |
POST | credits:read |
Calculate cost for an operation |
Demo Management Endpoints
Demos are free trial accounts with time-limited access. Duration is set globally by admin (
demo_duration_hours).
Each reseller has a daily limit (daily_demo_limit) set by admin.
| Endpoint | Method | Permission | Description |
|---|---|---|---|
/api/v1/demos |
GET | demos:read |
List demo users (supports ?status=active|expired) |
/api/v1/demos |
POST | demos:create |
Create demo user (free, no credits) |
/api/v1/demos/{id} |
GET | demos:read |
Get demo details with categories |
/api/v1/demos/{id} |
DELETE | demos:delete |
Delete a demo user |
List Users Query Parameters
| Parameter | Type | Description |
|---|---|---|
page |
integer | Page number (default: 1) |
limit |
integer | Items per page (default: 50, max: 100) |
search |
string | Search by username or email |
status |
string | Filter: active, inactive, expired, expiring |
expiring_days |
integer | Users expiring within N days (default: 7 when status=expiring) |
sort_by |
string | Sort field: created_at, expires_at, username |
sort_order |
string | Sort order: asc, desc (default: desc) |
Create User Request
{
"username": "newuser123",
"password": "securepassword",
"email": "user@example.com", // optional
"subscription_months": 3,
"max_devices": 5,
"categories": [1, 2, 3] // optional, category IDs
}
Extend Subscription Request
{
"days": 30 // number of days to add
}
Calculate Cost Request
{
"operation": "create_user",
"months": 3,
"devices": 5
}
// or for extension
{
"operation": "extend_user",
"days": 30,
"devices": 5
}
Success Response
{
"success": true,
"user": {
"id": 123,
"username": "newuser123",
"expires_at": "2026-03-01T00:00:00Z",
"max_devices": 5,
"is_active": true
},
"credits_used": 4.5,
"remaining_balance": 95.5
}
Update User Request
{
"email": "newemail@example.com", // optional
"password": "newpassword123", // optional
"max_devices": 5, // optional (1-10)
"active": true // optional
}
Reset Password Request
// Auto-generate password
{}
// Or set custom password
{
"new_password": "MyCustomPassword123!"
}
Reset Password Response
{
"success": true,
"new_password": "xK9#mNpQ2Rst",
"message": "Password reset successfully"
}
Update User Categories
{
"category_ids": [1, 2, 5, 8] // Array of category IDs
}
Create Demo Request
{
"username": "demo_user",
"password": "demo123456",
"email": "demo@example.com", // optional
"category_ids": [1, 2, 4] // optional, all categories if omitted
}
Demo Response
{
"id": 123,
"username": "demo_user",
"email": "demo@example.com",
"active": true,
"demo_expires_at": "2026-12-03T05:00:00Z",
"created_at": "2026-12-02T17:00:00Z",
"categories": [
{ "id": 1, "name": "VOD Movies", "type": "VOD" },
{ "id": 2, "name": "TV Channels", "type": "TV" },
{ "id": 4, "name": "Events", "type": "Eventos" }
]
}
List Demos with Filters
# List all demos
GET /api/v1/demos
# List only active demos
GET /api/v1/demos?status=active
# List expired demos
GET /api/v1/demos?status=expired
# With pagination
GET /api/v1/demos?page=1&limit=20
List Users with Filters
# Search users
GET /api/v1/users?search=john
# Get active users only
GET /api/v1/users?status=active
# Get users expiring in next 7 days
GET /api/v1/users?status=expiring&expiring_days=7
# Get expired users
GET /api/v1/users?status=expired
# Sort by expiration date
GET /api/v1/users?sort_by=expires_at&sort_order=asc
# Pagination
GET /api/v1/users?page=2&limit=25
Pagination Response
{
"users": [...],
"total": 150,
"pagination": {
"page": 1,
"limit": 50,
"total": 150,
"total_pages": 3,
"has_next": true,
"has_prev": false
}
}
Reseller API Keys Management
Endpoints for managing reseller API keys (require JWT authentication):
| Endpoint | Method | Description |
|---|---|---|
/api/reseller/api-keys |
GET | List all API keys for current reseller |
/api/reseller/api-keys |
POST | Create new API key |
/api/reseller/api-keys/{id} |
GET | Get API key details |
/api/reseller/api-keys/{id} |
PUT | Update API key settings |
/api/reseller/api-keys/{id} |
DELETE | Delete API key |
/api/reseller/api-keys/{id}/regenerate |
POST | Regenerate API key secret |
/api/reseller/api-keys/permissions |
GET | List available permissions |
Authentication Headers
For JWT-authenticated endpoints:
Authorization: Bearer <access_token>
Content-Type: application/json
For Public API v1 endpoints:
X-API-Key: <your_api_key>
Content-Type: application/json
Error Responses
{
"error": "Error message",
"code": "ERROR_CODE",
"status": 400
}
| Status | Description |
|---|---|
400 |
Bad Request - Invalid input |
401 |
Unauthorized - Invalid/expired token |
403 |
Forbidden - Insufficient permissions |
404 |
Not Found - Resource doesn't exist |
429 |
Too Many Requests - Rate limited |
500 |
Internal Server Error |
Troubleshooting
Solutions to common issues you may encounter.
Backend Issues
Backend won't start
- Check if port 3000 is already in use:
lsof -i :3000 - Verify Rust is installed:
rustc --version - Check .env file exists and has correct values
- Try:
cargo clean && cargo build --release
Database connection failed
- Check PostgreSQL service status:
docker compose ps postgres - Verify
DATABASE_URLmatches your PostgreSQL user/password/database - Check PostgreSQL logs:
docker compose logs -f postgres - Check
DATABASE_URLformat in .env
"Rust compilation errors"
- Update Rust:
rustup update - Clean build:
cargo clean - Check for missing system dependencies (openssl-dev, pkg-config)
Frontend Issues
Frontend can't connect to backend
- Verify
NEXT_PUBLIC_API_URLin frontend .env.local - Check if backend is running:
curl http://localhost:3000/api/health - Check CORS configuration if on different domains
- Ensure no firewall blocking the connection
Blank page or "Loading..." forever
- Open browser DevTools (F12) β Console for errors
- Check Network tab for failed API requests
- Clear browser cache and localStorage
- Try incognito/private browsing mode
"npm install" fails
- Delete
node_modulesandpackage-lock.json - Run
npm cache clean --force - Try
npm installagain - Ensure Node.js 20+ is installed
Authentication Issues
Can't login / "Invalid credentials"
- Default admin: username
admin, password fromADMIN_DEFAULT_PASSWORDenv or check console for auto-generated password - Check if user exists and is not disabled
- Check subscription hasn't expired
- Clear browser cookies and try again
2FA not working
- Ensure device time is synchronized (within 30 seconds)
- Use backup codes if available
- Admin can disable 2FA for a user in admin panel
Payment Issues
Stripe webhooks not working
- Verify webhook URL is publicly accessible
- Check
STRIPE_WEBHOOK_SECRETmatches Stripe dashboard - Test with Stripe CLI:
stripe listen --forward-to localhost:3000/api/payments/stripe/webhook - Check backend logs for webhook errors
Credits not added after payment
- Check Stripe dashboard for payment status
- Verify webhook is configured correctly
- Check backend logs for errors
- Admin can manually add credits if needed
Streaming Issues
Video playback issues
- Ensure stream URLs are accessible from client
- Check browser console for CORS errors
- Verify HLS/DASH streams are properly formatted
- Test stream URL directly in a desktop media player (VLC, MPV)
Buffering or slow playback
- Check stream server bandwidth
- Try lower quality if available
- Check client internet connection
- Consider using a CDN for content delivery
Android App Issues
Android TV/Phone app can't connect
- Create
Apps/tv_app/local.propertiesfromlocal.properties.templateand setbackend.url - For phone builds, also configure
Apps/phone_app/local.properties - For emulator use:
backend.url=http://10.0.2.2:3000 - Ensure backend allows HTTP (or configure HTTPS)
- Check
network_security_config.xmlfor cleartext traffic settings
Device registration fails
- Ensure device has internet connection
- Check if user has reached device limit
- Try uninstalling and reinstalling the app
- Check backend logs for errors
Login Backdrops (Frontend)
Customize the hero images shown on the login screen.
- Add your images to
frontend/public/backdrops/(recommended: PNG/WebP, 1280Γ720 or 1920Γ1080). - Option A (no code changes): Replace the existing
backdrop-*.pngfiles while keeping the same filenames. - Option B (edit from the Admin UI): Admin β System Configuration β Login Backdrops.
Paste a comma/newline-separated list of URLs or
/backdrops/*paths. This savesui_login_series_backdrops/ui_login_movies_backdropsin the database and the login page reads them fromGET /api/public/config/ui. - Option C (defaults in code): Edit
frontend/src/constants/backdrops.ts(arraysSERIES_BACKDROPS/MOVIES_BACKDROPS). - Use royalty-free or owned assets. If you generate images with AI, keep proof of your generatorβs commercial license/TOS for marketplace compliance.
- After changing assets/config, rebuild the frontend:
npm run buildthennpm run start(or your deploy pipeline).
Frequently Asked Questions
What are the minimum system requirements?
For a basic deployment: 2GB RAM, 10GB storage, 1 CPU core. For production with 1000+ users: 4GB+ RAM, SSD storage, 2+ CPU cores recommended.
Can I use a different database?
The current stack is designed for PostgreSQL. Using a different database engine requires custom development and is outside the standard package scope.
How do I change the admin password?
Login as admin β Profile (top right) β Change Password. If the password is lost, use the password reset flow (SMTP) or update the stored hash in PostgreSQL (see Backend Environment section).
What video formats are supported?
HLS (.m3u8), DASH (.mpd), and direct MP4/MKV streams. HLS is recommended for best compatibility across all platforms.
How do I enable HTTPS?
Use Nginx as a reverse proxy with Let's Encrypt certificates. See the Deployment section for configuration.
Can I run multiple instances for high availability?
Yes, with PostgreSQL and proper infrastructure. Use a shared database instance and put frontend/backend behind a load balancer or reverse proxy.
How do I backup the database?
Use PostgreSQL backup tools, for example:
pg_dump "$DATABASE_URL" > backup/iptv_$(date +%Y%m%d).sql. You can also enable
automatic backups via BACKUP_ENABLED / BACKUP_DIR in
backend/.env.
What browsers are supported?
Chrome 80+, Firefox 75+, Safari 13+, Edge 80+. Mobile browsers (Chrome/Safari on iOS/Android) are also supported.
Can I customize the UI colors/theme?
Yes! Edit the CSS variables in frontend/src/app/globals.css or the Tailwind config. The
app supports both dark and light themes.
How do I add new languages?
Add translation files in frontend/src/locales/. Copy an existing locale folder (e.g.,
en.json) and translate the strings. Update the language selector in i18n.ts.
Is the Android app compatible with Android TV?
Yes. StreamCore includes a dedicated Android TV app (Apps/tv_app) with Leanback and
D-pad
navigation, and a dedicated Android Phone app (Apps/phone_app) for phone/tablet UX.
How does the credit system work?
Resellers purchase credits via Stripe. Creating users costs credits based on subscription months and
device count: months Γ (1 + (devices - 3) Γ 0.25). Example: 1 month with 3 devices = 1
credit. Volume discounts apply to bulk purchases.
Can I disable certain features?
Yes, many features can be toggled in Admin β Settings. You can also hide UI elements by editing the frontend components.
How do I import content from M3U playlists?
Go to Admin β Content β Import, paste your M3U/M3U8 URL, and the system will parse and import all channels with categories.
What's the device limit per user?
Configurable per user (default 1-5). Admin can set global defaults in Settings. Users can manage their devices in their profile.
Credits & Licenses
StreamCore is built with the following open-source libraries and services:
Frontend (Web)
| Library | License | Purpose |
|---|---|---|
| Next.js | MIT | React framework |
| React | MIT | UI library |
| Tailwind CSS | MIT | Utility-first CSS |
| shadcn/ui | MIT | UI components |
| Lucide Icons | ISC | Icon library |
| hls.js | Apache 2.0 | HLS playback |
| Shaka Player | Apache 2.0 | DASH/HLS playback |
| i18next | MIT | Internationalization |
Backend (Rust)
| Library | License | Purpose |
|---|---|---|
| Axum | MIT | Web framework |
| Tokio | MIT | Async runtime |
| Serde | MIT/Apache 2.0 | Serialization |
| SQLx | MIT/Apache 2.0 | Database |
| jsonwebtoken | MIT | JWT authentication |
| Lettre | MIT | Email sending |
Android App (Kotlin)
| Library | License | Purpose |
|---|---|---|
| Jetpack Compose | Apache 2.0 | UI toolkit |
| AndroidX Media3 | Apache 2.0 | Video playback (ExoPlayer successor) |
| Media3 ExoPlayer | Apache 2.0 | Video playback engine |
| FFmpeg Extension | Apache 2.0 | Software decoding fallback |
| Hilt | Apache 2.0 | Dependency injection |
| Retrofit | Apache 2.0 | HTTP client |
| Coil | Apache 2.0 | Image loading |
Third-Party Services
| Service | Purpose |
|---|---|
| Stripe | Payment processing |
| TMDB | Movie/TV metadata |
| Google Fonts | Inter & JetBrains Mono fonts |
Fonts
- Inter - Open Font License (OFL)
- JetBrains Mono - OFL
Support
Getting Help
If you encounter issues not covered in this documentation:
- Check the Troubleshooting section
- Review the FAQ
- Check backend/frontend logs for error messages
- Search existing issues on the support portal
Reporting Issues
When reporting issues, please include:
- StreamCore version number
- Operating system and version
- Browser/device information (if applicable)
- Steps to reproduce the issue
- Error messages from logs (if any)
- Screenshots (if applicable)
Feature Requests
We welcome feature requests and suggestions. Please describe:
- What feature you'd like to see
- Why it would be useful
- Any implementation ideas you have
For technical support, please use the support system on the marketplace where you purchased StreamCore.
Thank You!
Once again, thank you for purchasing StreamCore IPTV. We hope this documentation has been helpful. If you have any questions or need assistance, please don't hesitate to reach out through the CodeCanyon support system.
We appreciate your business and wish you success with your streaming platform!